/*
 Copyright (c) 2013 MeherTJ G. All rights reserved.
 License: LGPL for personnal study or free software.
 */

#pragma once

#include <cstdio>
#include <cstdlib>
#include <string>
#include <vector>
#include <fstream>

namespace Zen
{
	namespace File
	{
		// Get the tail after last {sign}.
		inline std::string GetFilePathExtention(std::string const& path, char sign = '.')
		{
			auto pos = path.find_last_of(sign);
			if (pos == path.npos) return "";
			return path.substr(pos + 1);
		}

		// Get file size.
		inline std::fstream::pos_type GetStreamSize(std::fstream& stream)
		{
			stream.seekg(0, std::ios::end);
			auto size = stream.tellg();
			if (size < 0)
				return 0;
			else
				return size;
		}

		// read all to string from the {stream}
		inline std::string LoadStreamToString(std::fstream& stream)
		{
			std::string str;
			str.reserve((std::string::size_type)GetStreamSize(stream));
			stream.seekg(0);

			int c = 0;
			while ((c = stream.get()) > 0) str.push_back((char)c);
			return str;
		}

		// read all to binary buffer from {stream}
		inline std::vector<uint8_t> LoadStreamToBuffer(std::fstream& stream)
		{
			std::vector<uint8_t> value;
			value.resize((std::string::size_type)GetStreamSize(stream));
			stream.seekg(0);

			stream.read((char*)value.data(), value.size());
			if (stream.gcount() != value.size())
			{
				value.clear();
			}
			return value;
		}

		// read buffer from the file {path} as binary.
		inline std::vector<uint8_t> LoadFileToBuffer(std::string const& path)
		{
			std::fstream s(path, std::ios::in | std::ios::binary);
			if (!s) return {};
			return LoadStreamToBuffer(s);
		}

		// read string from the file {path} as text.
		inline std::string LoadFileToString(std::string const& path)
		{
			std::fstream s(path, std::ios::in);
			if (!s) return "";
			return LoadStreamToString(s);
		}

		/// write buffer to binary file.
		inline bool WriteBufferToFile(std::string const& path, void const* value, size_t size)
		{
			std::fstream s(path, std::ios::out | std::ios::binary);
			if (!s) return false;
			return s.write((const char*)value, size).good();
		}

		// write buffer {value} to binary file.
		inline bool WriteBufferToFile(std::string const& path, std::vector<uint8_t> const& value)
		{
			return WriteBufferToFile(path, value.data(), value.size());
		}

		// append buffer to binary file {path}.
		inline bool AppendBufferToFile(std::string const& path, void const* value, size_t size)
		{
			std::fstream s(path, std::ios::out | std::ios::binary | std::ios::app);
			if (!s) return {};
			return s.write((const char*)value, size).good();
		}

		// append buffer to binary file {path}.
		inline bool AppendBufferToFile(std::string const& path, std::vector<uint8_t> const& value)
		{
			return AppendBufferToFile(path, value.data(), value.size());
		}

		// append string to text file {path}.
		inline bool AppendStringToFile(std::string const& path, void const* value, size_t size)
		{
			std::fstream s(path, std::ios::out | std::ios::app);
			if (!s) return false;
			return s.write((const char*)value, size).good();
		}

		// append string to text file {path}.
		inline bool AppendStringToFile(std::string const& path, std::string const& value)
		{
			std::fstream s(path, std::ios::out | std::ios::app);
			if (!s) return false;
			return s.write((char const*)value.data(), value.size()).good();
		}

		// write string to text file.
		inline bool WriteStringToFile(std::string const& path, void const* value, size_t size)
		{
			std::fstream s(path, std::ios::out);
			if (!s) return false;
			return s.write((char const*)value, size).good();
		}

		// write string to text file.
		inline bool WriteStringToFile(std::string const& path, std::string const& value)
		{
			return AppendStringToFile(path, value.data(), value.size());
		}
	} // namespace File
} // namespace Zen
